#include "StdAfx.h"
#include "VideoPlayerManager.h"
#include <string>
#define REFERENCE_TIME_UNIT 10000000
#define MAX_SIZE			256





DEFINE_GUID(CLSID_MyFreeSync,
			0xfd501041, 0x8ebe, 0x11ce, 0x81, 0x83, 0x00, 0xaa, 0x00, 0x57, 0x7d, 0xa2); // MyFree Codec Filter


VideoPlayerManager::VideoPlayerManager(void)
{
	m_state = STATE_NO_GRAPH;
	m_lTotalDuration=0;
	m_fStep=0;
	m_lTimeElapsed=0;
	m_nPos=0;
	m_wnd = NULL;

}

VideoPlayerManager::~VideoPlayerManager(void)
{
}

BOOL VideoPlayerManager::MultiMedia_Initialize(CString strPathName)
{
	m_strMediaFilePath = strPathName;
	m_strSubtitleFilePath = "";

	int curPos = m_strMediaFilePath.ReverseFind(_T('.'));

	m_strSubtitleFilePath =  m_strMediaFilePath.Left(curPos) + _T(".smi");
	
	CFileStatus status;
	if (!CFile::GetStatus(m_strSubtitleFilePath, status))
	{
		m_strSubtitleFilePath = m_strMediaFilePath.Left(curPos) + _T(".sami");
		if (!CFile::GetStatus(m_strSubtitleFilePath, status))
			m_strSubtitleFilePath = "";
		
	}

	 
	HRESULT hr;
	
	//create instance and query interface
	hr=CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,IID_IGraphBuilder, (void **)&pGraphBuilder);

	if(FAILED(hr))
	{
		SAFE_RELEASE(pGraphBuilder);
		CoUninitialize();
		return FALSE;
	}
	hr = pGraphBuilder->QueryInterface(IID_IMediaControl, (void **)&pMediaControl);
	hr = pGraphBuilder->QueryInterface(IID_IMediaSeeking, (void**)&pMediaSeeking);
	hr = pGraphBuilder->QueryInterface(IID_IMediaEventEx, (void**)&pMediaEventEx);
	hr = pGraphBuilder->QueryInterface(IID_IBasicAudio,	  (void**)&pAudio);
	
		pMediaEventEx->SetNotifyWindow((OAHWND)m_wnd->m_hWnd,WM_GRAPHNOTIFY,0);

	if (!pMediaControl || !pMediaSeeking || !pMediaEventEx || !pAudio)
	{
		SAFE_RELEASE(pMediaControl);
		SAFE_RELEASE(pMediaSeeking);
		SAFE_RELEASE(pMediaEventEx);
		SAFE_RELEASE(pAudio);
		return FALSE;
	}
	m_state = STATE_STOPPED;
	return TRUE;
}

void VideoPlayerManager::MultiMedia_Clean()
{
	if (m_state == STATE_NO_GRAPH) return;

	//MultiMedia_Stop();
	if (pMediaEventEx != NULL)
	{
		pMediaEventEx->SetNotifyWindow((OAHWND)NULL, NULL, NULL);
	}

	SAFE_RELEASE(pGraphBuilder);
	SAFE_RELEASE(pMediaControl);
	SAFE_RELEASE(pMediaSeeking);
	SAFE_RELEASE(pMediaEventEx);
	SAFE_RELEASE(pAudio);

	//-------------------------
	if(pVmr)
	{
		//pVmr->Release();
		pVmr = NULL;
	}
	if(pWC)
	{
		//pWC->Release();
		pWC = NULL;
	}
	if(pConfig)
	{
		//pConfig->Release();
		pConfig = NULL;
	}
	if(pAr)
	{
		//pConfig->Release();
		pAr = NULL;
	}
	/*IBaseFilter   *pSAMI;
	HRESULT hr = pGraphBuilder->FindFilterByName(L"SAMI (CC) Parser", &pSAMI);
	if (hr ==S_OK)
		pGraphBuilder->RemoveFilter(pSAMI);
	SAFE_RELEASE(pSAMI);*/
	m_state = STATE_NO_GRAPH;
	
}

BOOL VideoPlayerManager::MultiMedia_Play()
{

	/*if (m_state != STATE_PAUSED && m_state != STATE_STOPPED)
    {
        return FALSE;
    }*/

	if(PlayBack())
	{
		m_state = STATE_RUNNING;
		return TRUE;
	}
	return FALSE;
}

BOOL VideoPlayerManager::MultiMedia_Pause()
{
	HRESULT hr = pMediaControl->Pause();
	if(FAILED(hr))
		return FALSE;
	m_state = STATE_PAUSED;
	return TRUE;
}

BOOL VideoPlayerManager::MultiMedia_Stop() 
{
	if (m_state == STATE_NO_GRAPH)
    {
        return FALSE;
    }
		

	HRESULT hr = pMediaControl->Stop();
	if(FAILED(hr))
		return FALSE;
	m_state = STATE_STOPPED;
	m_lTimeElapsed=0;
	return TRUE;
}
BOOL VideoPlayerManager::MultiMedia_Resume() 
{
	HRESULT hr;
	hr = pMediaControl->Run();
	if(FAILED(hr))
		return FALSE;
	return TRUE;
}

BOOL VideoPlayerManager::PlayBack()
{
	HRESULT hr;
	
	MultiMedia_Clean();
	MultiMedia_Initialize(m_strMediaFilePath);
	

	hr = BuildFilterGraph(m_wnd, m_rtPlayer);
	
	if(pMediaControl->Run())
		return TRUE;	
	else
	 return FALSE;
}

void VideoPlayerManager::RenderVideoToWindowless(CWnd *pParentWnd, CRect pRect)
{
	HRESULT hr;
	//create VMR9 filter
	hr = CoCreateInstance(CLSID_VideoMixingRenderer9,NULL,CLSCTX_INPROC,IID_IBaseFilter,(void**)&pVmr);
	if(FAILED(hr))
	{
		//pVmr->Release();
		//pVmr=NULL;
		SAFE_RELEASE(pVmr);
		CoUninitialize();
	}
	pGraphBuilder->AddFilter(pVmr,L"VideoMixingRender9");
	pVmr->QueryInterface(IID_IVMRFilterConfig9,(void **)&pConfig);
	pConfig->SetRenderingMode(VMR9Mode_Windowless);
	pVmr->QueryInterface(IID_IVMRWindowlessControl9,(void**)&pWC);
	//pWC->SetVideoPosition(NULL, pRect);
	pWC->SetVideoClippingWindow(pParentWnd->m_hWnd);
	pWC->SetAspectRatioMode(VMR9ARMode_LetterBox);
	
	
}

HRESULT VideoPlayerManager::UpdateVideoWindow(const LPRECT prc)
{
	if (pWC == NULL) return S_FALSE;
	if (prc)
    {
        return pWC->SetVideoPosition(NULL, prc);
    }
    else
    {

        RECT rc;
		GetClientRect(m_wnd->GetSafeHwnd(), &rc);
        return pWC->SetVideoPosition(NULL, &rc);
    }
}

void VideoPlayerManager::SetFilePath(CString strPath)
{
	m_strMediaFilePath=strPath;
}
void VideoPlayerManager::SetWindowParent(CWnd *wnd)
{
	m_wnd=wnd;
}
void VideoPlayerManager::SetRectPlayer(CRect rtPlayer)
{
	m_rtPlayer=rtPlayer;
}

CString VideoPlayerManager::GetTimeDuration()
{
	long temporary;
	char totalTime[MAX_SIZE];
	m_lTotalDuration = m_length/REFERENCE_TIME_UNIT;
	temporary=(long)m_lTotalDuration;
	m_fStep =(float)100/temporary;
	sprintf(totalTime, "%02u:%02u:%02u", (temporary/3600)%60, (temporary/60)%60, (temporary%60));
	CString strTotalTime(totalTime);
	return strTotalTime;
}

CString VideoPlayerManager::GetTimeElapsedOfMedia()
{
	char time[MAX_SIZE]="";
	m_lTimeElapsed++;
	if(m_lTimeElapsed>=m_lTotalDuration)
		m_lTimeElapsed=m_lTotalDuration;
	m_nPos=(int)((float)m_fStep*(float)m_lTimeElapsed);
	sprintf(time, "%02u:%02u:%02u", (m_lTimeElapsed/3600)%60, (m_lTimeElapsed/60)%60, m_lTimeElapsed%60);
	CString strTime(time);
	if(m_lTimeElapsed>=m_lTotalDuration)
		m_nPos=MAX_RANGE_SEEK_SLIDER;
	return strTime;
}

long VideoPlayerManager::GetVolume()
{
	long lVolume;
	HRESULT hr= pAudio->get_Volume(&lVolume);
	if(FAILED(hr))
		return 0;
	return lVolume;
}

bool VideoPlayerManager::SetVolume(long lVol)
{
	HRESULT hr= pAudio->put_Volume(lVol);
	if(FAILED(hr))
		return false;
	return true;
}

CString VideoPlayerManager::SetPosition(int nPos)
{

	LONGLONG lTimeLineUnit =0;
	REFERENCE_TIME rtTime;

	lTimeLineUnit=m_length/MAX_RANGE_SEEK_SLIDER; //slide range[0-100]
	rtTime=lTimeLineUnit*nPos;
	pMediaSeeking->SetPositions(&rtTime, AM_SEEKING_AbsolutePositioning,NULL,AM_SEEKING_NoPositioning);
	m_lTimeElapsed=rtTime/10000000;

	char time[MAX_SIZE] = "";
	sprintf(time, "%02u:%02u:%02u", (m_lTimeElapsed/3600)%60, (m_lTimeElapsed/60)%60, m_lTimeElapsed%60);
	CString strTime(time);
	return strTime;
}
CString VideoPlayerManager::SetPosition2(LONGLONG cur)
{

	pMediaSeeking->SetPositions(&cur, AM_SEEKING_AbsolutePositioning,NULL,AM_SEEKING_AbsolutePositioning);
	m_lTimeElapsed=cur/10000000;

	char time[MAX_SIZE] = "";
	sprintf(time, "%02u:%02u:%02u", (m_lTimeElapsed/3600)%60, (m_lTimeElapsed/60)%60, m_lTimeElapsed%60);
	CString strTime(time);
	return strTime;
}

HRESULT VideoPlayerManager::AddSubtitleFitler()
{
	HRESULT hr; 
	 
	if (pGraphBuilder && m_strSubtitleFilePath != "")
	{
		__try
		{
			hr = pGraphBuilder->RenderFile(m_strSubtitleFilePath, NULL);
			
		}
		__except (EXCEPTION_EXECUTE_HANDLER) 
		{
			hr = E_FAIL;
			return hr;
		}	
	}

	//return hr;
}




bool VideoPlayerManager::IsSubtitleAvailable()
{
	bool result = false;

	HRESULT hr; 
	if (pGraphBuilder)
	{
		IBaseFilter   *pSAMI;
		hr = pGraphBuilder->FindFilterByName(L"SAMI (CC) Parser", &pSAMI);
	}

	if (hr == S_OK)
		result = true;

	return result;
}
HRESULT VideoPlayerManager::BuildFilterGraph(CWnd *pParentWnd, CRect pRect)
{
	HRESULT hr;
	int nPinNo = 0;

	RenderVideoToWindowless(pParentWnd,pRect);

	// Add the DSound Renderer to the graph.
	hr = CoCreateInstance(CLSID_DSoundRender, NULL, CLSCTX_INPROC, IID_IBaseFilter, (LPVOID *)&pAr);
	if(FAILED(hr)) 
		goto Exit_Build_Graph;
	

	hr = pGraphBuilder->AddFilter(pAr, L"Default DirectSound Device");
	if(FAILED(hr)) 
		goto Exit_Build_Graph;

	hr = BuildGraphUsingDefault();
	
	if (hr != S_OK)
	{
	
		//Add myfreecodecpack filter
		int sizeOfString = (m_strMediaFilePath.GetLength() + 1);
		LPWSTR  lpsz = new TCHAR[sizeOfString];
		_tcscpy_s(lpsz, sizeOfString, m_strMediaFilePath);

		
		hr = CoCreateInstance(CLSID_MyFreeSync, NULL, CLSCTX_INPROC, IID_IBaseFilter, (LPVOID *)&pRd);
		hr = pGraphBuilder->AddFilter(pRd, L"MyFree Reader-Sync Filter");
		if(FAILED(hr))
		{
			m_ssFreeCodec.DeleteFilter(pGraphBuilder, pRd, 0);
			pRd = NULL;
			goto Exit_Build_Graph;
		}

		IFileSourceFilter *pSF;
		hr = pRd->QueryInterface(IID_IFileSourceFilter, (void **)&pSF);
		hr = pSF->Load((LPOLESTR)lpsz, NULL);
		SAFE_RELEASE(pSF);
		delete[] lpsz;

		//Connect Source fitler & Audio filter
		hr = m_ssFreeCodec.ConnectFilters(pGraphBuilder, pRd, ++nPinNo, pAr, 1, (LPSTR)-1, FALSE);
		if(FAILED(hr))
		{
			m_ssFreeCodec.DeleteFilter(pGraphBuilder, pAr, 0);
			pAr = NULL;
			nPinNo--;
			goto Exit_Build_Graph;
		}
				 
		// Add the Video Renderer to the graph.
		hr = m_ssFreeCodec.ConnectFilters(pGraphBuilder, pRd, ++nPinNo, pVmr, 1, (LPSTR)-1, FALSE);	
		if(FAILED(hr))
		{
			m_ssFreeCodec.DeleteFilter(pGraphBuilder, pVmr, 0);
			pVmr = NULL;
			nPinNo--;
			goto Exit_Build_Graph;
		}

		pMediaControl->Run();
		pMediaControl->Pause();
	}
	pMediaSeeking->GetDuration(&m_length);
	AddSubtitleFitler();
	
Exit_Build_Graph:
	
	/*if(pRd)
	{
		pRd->Release();
	}
	if(pVmr)
	{
		pVmr->Release();
	}
	if(pAr)
	{
		pAr->Release();
	}
	if(pWC)
	{
		SAFE_RELEASE(pWC);
	}
	if(pConfig)
	{
		SAFE_RELEASE(pConfig);
	}*/
	return hr;
}

HRESULT VideoPlayerManager::BuildGraphUsingDefault()
{
	HRESULT hr;
	__try
	{
		hr = pGraphBuilder->RenderFile((LPCWSTR)m_strMediaFilePath,NULL);
		
	}
	__except (EXCEPTION_EXECUTE_HANDLER) 
	{
		hr = E_FAIL;
		return hr;
	}
	return hr;
}
